package com.cqemme.hardwareservice.component;

import com.alibaba.fastjson.JSONObject;
import com.cqemme.comm.po.Result;
import com.cqemme.hardwareservice.feign.SchoolServiceFeign;
import com.cqemme.hardwareservice.util.EmptyChecker;
import com.cqemme.hardwareservice.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 校徽tcp推地址信息接收类
 *
 * @author daibin
 */
@Component
@Slf4j
public class TcpMutualComponent implements CommandLineRunner {

    @Value("${other.api.getLonLat}")
    private String getLonLatUrl;


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Resource
    private SchoolServiceFeign schoolServiceFeign;

    /**
     * 开启tcp
     *
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) {
        try {
            ServerSocket s = new ServerSocket(9014);
            while (true) {
                //等待连接 - 堵塞等待
                Socket socket = s.accept();
                //有连接来就开一个线程跑这个连接的数据
                runThread(s, socket);
            }
        } catch (Exception e) {
            log.error("socket异常：{}", e);
        }

    }

    /**
     * 一个处理tcp连接的线程
     *
     * @param s
     * @param socket
     */
    public void runThread(ServerSocket s, Socket socket) {
        log.info("有连接进来");
        Runnable thread = new Runnable() {
            @Override
            public void run() {
                //输进流 - 客户端请求数据流
                BufferedReader br = null;
                //回复流
                PrintWriter pw = null;
                try {
                    br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    //用于发送返回信息,可以不需要装饰这么多io流使用缓冲流时发送数据要注意调用.flush()方法
                    pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
                    Map<String, Object> dataMap = new HashMap<>();
                    while (true) {
                        //长连接 - 一直监听流的变化 - 流没得变化就一直在这堵塞等流的变化
                        String str = br.readLine();
                        log.info("数据：{}", str);
                        if (EmptyChecker.notEmpty(str)) {
                            handleData(dataMap, str, pw, br);
                        }
                        if (str == null) {
                            //说明此连接被中断 - 关闭 - 跳出while去回收资源
                            break;
                        }
                    }

                } catch (Exception e) {

                } finally {
                    try {
                        br.close();
                        pw.close();
                        socket.close();
                        //s.close();
                    } catch (Exception e2) {

                    }
                }
            }
        };
        new Thread(thread).start();
    }

    /**
     * 处理推送数据
     *
     * @param dataMap pw.println(message);
     * @param str
     */
    public void handleData(Map<String, Object> dataMap, String str, PrintWriter pw, BufferedReader br) {
        if (EmptyChecker.isEmpty(str)) {
            return;
        }
        if (str.startsWith("POST")) {
            str = str.replace("POST", "");
            dataMap.put("POST", str);
            return;
        } else if (str.startsWith("post")) {
            str = str.replace("post", "");
            dataMap.put("POST", str);
            return;
        }
        int endIndex = str.indexOf("]");
        if (str.startsWith("[") && (endIndex > 3)) {
            //解析成细节
            //String str2 = str.replace("[", "").replace("]", "");
            String str2 = str.substring(1, endIndex);
            String[] dataArr = str2.split(",");
            String sendType = dataArr[1].toUpperCase();
            if ("T166".equals(sendType)) {
                //协议是T166处理
                handleT166(dataMap, str2.split("#"), str);
            } else if ("T167".equals(sendType)) {
                //协议是T167处理
                handleT167(dataMap, dataArr, str);
            }
            try {
                //根据设备id取学生信息
                Result student = schoolServiceFeign.findByImeiNo(Long.parseLong(dataMap.get("IMEI-id").toString().trim()));
                //Result student = null;
                if (EmptyChecker.notEmpty(student) && EmptyChecker.notEmpty(student.getData())) {
                    int studentId = Integer.parseInt(((Map) student.getData()).get("id") + "");
                    //String url = getStudentAll + "?id=" + studentId;
                    //根据学生信息在node取学生人物关系数据
                    //Result studentOth = null;
                    //studentOth = restTemplate.getForObject(url, Result.class);
                    //if (EmptyChecker.isEmpty(studentOth.getData())) {
                    //    studentOth = schoolServiceFeign.selectByStudentId(studentId);
                    //    dataMap.put("studentRelation", studentOth.getData());
                    //}
                    //根据学生id在学校服务取学生人物关系数据
                    Result studentOth = schoolServiceFeign.selectByStudentId(studentId);
                    dataMap.put("studentRelation", studentOth.getData());
                    dataMap.put("Student", student.getData());
                    //存mq - 给node消费
                    //log.info("存mongoodb");
                    try {
                        log.info("报警字段：：{}", dataMap.get("Sos-Sign"));
                    } catch (Exception e) {
                    }
                    amqpTemplate.convertAndSend("student-location", JSONObject.toJSONString(dataMap));
                    if (EmptyChecker.notEmpty(dataMap.get("Gps")) &&
                            EmptyChecker.notEmpty(((List<Map<String, String>>) dataMap.get("Gps")).get(0).get("Latitude"))
                    ) {
                        //存mq - 给熊涛涛消费
                        amqpTemplate.convertAndSend("student-location-to-app", JSONObject.toJSONString(dataMap));
                    }
                }
            } catch (Exception e) {
                log.error("服务处理失败", e);
            } finally {
                try {
                    //回复内容
                    callMsg(dataMap, pw);
                    //清除这个map
                    dataMap.clear();
                    handleData(dataMap, str.substring(endIndex + 1), pw, br);
                } catch (Exception e) {
                }
            }
            return;
        }
        String[] split = str.split(":");
        dataMap.put(split[0], split[1]);
    }

    /**
     * 协议是T166的数据处理
     *
     * @param dataMap
     * @param dataArr
     */
    public void handleT166(Map<String, Object> dataMap, String[] dataArr, String str) {
        try {
            //流水号 协议 报文长度 NB信号强度
            String d0 = dataArr[0];
            String[] d0Arr = d0.split(",");
            dataMap.put("Serial-Number", d0Arr[0]);
            dataMap.put("Send-Type", d0Arr[1]);
            dataMap.put("Send-Length", d0Arr[2]);
            dataMap.put("Nb-Strength", d0Arr[3]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[0]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //电量
            dataMap.put("Electricity", dataArr[1]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[1]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //步数
            dataMap.put("Step-Count", dataArr[2]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[2]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //gps点内容
            String d4 = dataArr[4];
            String[] gpsArr = d4.split("!");
            List<Map<String, String>> gpsList = new ArrayList<>();
            for (int i = 0; i < gpsArr.length; i++) {
                try {
                    String gpsStr = gpsArr[i];
                    Map<String, String> gps = new HashMap<>();
                    //gps状态 0：表示定位成功,GPS位置  1：表示WIFI定位失败  2：表示WIFI定位成功-GPS未打开或GPS位置暂不用等其它情况
                    gps.put("Gps-Status", gpsStr.substring(0, 1));
                    //经度标识  E：表示东经    W：表示西经
                    gps.put("Longitude-Type", gpsStr.substring(1, 2));
                    int nI = 0;
                    if ((nI = gpsStr.indexOf("N")) > 3) {
                    } else if ((nI = gpsStr.indexOf("S")) > 3) {
                    } else if ((nI = gpsStr.indexOf("n")) > 3) {
                    } else if ((nI = gpsStr.indexOf("s")) > 3) {
                    }
                    //经度
                    gps.put("Longitude", gpsStr.substring(2, nI));
                    //维度标识
                    gps.put("Latitude-Type", gpsStr.substring(nI, nI + 1));
                    int tI = 0;
                    if ((tI = gpsStr.indexOf("T")) > 3) {
                    } else if ((nI = gpsStr.indexOf("t")) > 3) {
                    }
                    //维度
                    gps.put("Latitude", gpsStr.substring(nI + 1, tI));
                    //时间
                    gps.put("Time", gpsStr.substring(tI + 1));
                    gpsList.add(gps);
                } catch (Exception e) {
                }
            }
            dataMap.put("Gps", gpsList);
        } catch (Exception e) {
            log.error("T166-解析dataArr[4]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //Wifi点内容
            String d3 = dataArr[3];
            String[] wifiArr = d3.split("!");
            Map<String, Object> wifi = new HashMap<>();
            wifi.put("Wifi-Time", wifiArr[0].replace(",", ""));
            List<Map<String, String>> wifiList = new ArrayList<>();
            for (int i = 1; i < wifiArr.length; i++) {
                try {
                    Map<String, String> wifiContentMap = new HashMap<>();
                    String[] wifiContentArr = wifiArr[i].split(",");
                    //wifi名称
                    wifiContentMap.put("Wifi-Name", wifiContentArr[0]);
                    //wifi Mac地址
                    wifiContentMap.put("Wifi-Mac", wifiContentArr[1]);
                    //wifi 信号强度
                    wifiContentMap.put("Wifi-Strength", wifiContentArr[2]);
                    wifiList.add(wifiContentMap);
                } catch (Exception e) {
                }
            }
            wifi.put("Wifi-Content", wifiList);
            dataMap.put("Wifi", wifi);
            try {
                if (EmptyChecker.isEmpty(dataMap.get("Gps")) ||
                        EmptyChecker.isEmpty(((List<Map<String, String>>) dataMap.get("Gps")).get(0).get("Latitude"))
                ) {
//                    Map<String,String> faWifi=new HashMap<>();
//                    faWifi.put("Wifi-Mac","34:cd:6d:f7:c0:30");
//                    wifiList.add(faWifi);
                    if (EmptyChecker.notEmpty(wifiList) &&
                            EmptyChecker.notEmpty(wifiList.get(0).get("Wifi-Mac"))
                    ) {
                        handleGps(dataMap, wifiList);
                    }
                }
            } catch (Exception e) {
            }
        } catch (Exception e) {
            log.error("T166-解析dataArr[3]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //参数同步标签1
            dataMap.put("Parameter-Label", dataArr[5]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[5]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //SOS标识 0-无报警；1- SOS键报警；2-低电压报警；3-关机报警
            dataMap.put("Sos-Sign", dataArr[6]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[6]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //Gsensor读取次数
            dataMap.put("Gsensor-Count", dataArr[7]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[7]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //wifi搜索次数
            dataMap.put("Wifi-Search-Count", dataArr[8]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[8]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //定时启动次数
            dataMap.put("Start-Count", dataArr[9]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[9]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //上报次数
            dataMap.put("Report-Count", dataArr[10]);
        } catch (Exception e) {
            log.error("T166-解析dataArr[10]失败", e);
            log.error("T166-源字符串:" + str);
        }
        try {
            //软件版本号
            dataMap.put("App-Version", dataArr[11]);
        } catch (Exception e) {

        }
    }

    /**
     * 协议是T167的数据处理
     *
     * @param dataMap
     * @param dataArr
     */
    public void handleT167(Map<String, Object> dataMap, String[] dataArr, String str) {
        try {
            //流水号 协议 报文长度 NB信号强度
            dataMap.put("Serial-Number", dataArr[0]);
            dataMap.put("Send-Type", dataArr[1]);
            dataMap.put("Send-Length", dataArr[2]);
        } catch (Exception e) {
            log.error("T167-解析dataArr[0、1、2]失败", e);
            log.error("T167-源字符串:" + str);
        }
        try {
            //gps点内容
            String d3 = dataArr[3];
            String[] gpsArr = d3.split("!");
            List<Map<String, String>> gpsList = new ArrayList<>();
            for (int i = 0; i < gpsArr.length; i++) {
                try {
                    String gpsStr = gpsArr[i];
                    Map<String, String> gps = new HashMap<>();
                    //gps状态 0：表示定位成功,GPS位置  1：表示WIFI定位失败  2：表示WIFI定位成功-GPS未打开或GPS位置暂不用等其它情况
                    gps.put("Gps-Status", gpsStr.substring(0, 1));
                    //经度标识  E：表示东经    W：表示西经
                    gps.put("Longitude-Type", gpsStr.substring(1, 2));
                    int nI = 0;
                    if ((nI = gpsStr.indexOf("N")) > 3) {
                    } else if ((nI = gpsStr.indexOf("S")) > 3) {
                    } else if ((nI = gpsStr.indexOf("n")) > 3) {
                    } else if ((nI = gpsStr.indexOf("s")) > 3) {
                    }
                    //经度
                    gps.put("Longitude", gpsStr.substring(2, nI));
                    //维度标识
                    gps.put("Latitude-Type", gpsStr.substring(nI, nI + 1));
                    int tI = 0;
                    if ((tI = gpsStr.indexOf("T")) > 3) {
                    } else if ((nI = gpsStr.indexOf("t")) > 3) {
                    }
                    //维度
                    gps.put("Latitude", gpsStr.substring(nI + 1, tI));
                    //时间
                    gps.put("Time", gpsStr.substring(tI + 1));
                    gpsList.add(gps);
                } catch (Exception e) {
                }
            }
            dataMap.put("Gps", gpsList);
        } catch (Exception e) {
            log.error("T167-解析dataArr[3]失败", e);
            log.error("T167-源字符串:" + str);
        }
    }

    /**
     * 处理wifi转Gps
     *
     * @param dataMap
     */
    public void handleGps(Map<String, Object> dataMap, List<Map<String, String>> wifiList) {
        try {
            for (int i = 0; i < wifiList.size(); i++) {
                Map<String, String> wifi = wifiList.get(i);
                if (EmptyChecker.notEmpty(wifi.get("Wifi-Mac"))) {
                    MultiValueMap<String, String> par = new LinkedMultiValueMap<>();
                    par.add("bssid", wifi.get("Wifi-Mac"));
                    Map resMap = restTemplate.postForObject(getLonLatUrl, par, Map.class);
                    if (EmptyChecker.notEmpty(resMap)) {
                        Map valMap = (Map) ((List) resMap.get("values")).get(0);
                        String lng = valMap.get("lng").toString();
                        String lat = valMap.get("lat").toString();
                        if (EmptyChecker.notEmpty(lng) && EmptyChecker.notEmpty(lat) && !"0".equals(lng) && !"0".equals(lat)) {
                            List<Map<String, String>> gpsList = new ArrayList<>();
                            Map<String, String> gps = new HashMap<>();
                            //经度
                            gps.put("Longitude", lng);
                            //维度
                            gps.put("Latitude", lat);
                            //地址
                            gps.put("Address", valMap.get("address").toString().split(";")[0]);
                            gpsList.add(gps);
                            dataMap.put("Gps", gpsList);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
        }
    }

    /**
     * 回复硬件方
     *
     * @param dataMap
     * @param pw
     */
    public void callMsg(Map<String, Object> dataMap, PrintWriter pw) {
        //报文体
        StringBuilder body = new StringBuilder();
        String sendType = dataMap.get("Send-Type") + "";
        //回复定位失败与否
        Integer pro = ("T167".equals(sendType) || "t167".equals(sendType)) ? 0 : 2;
        String LongitudeType = "E";
        String Longitude = "0";
        String DimensionType = "N";
        String Dimension = "0";
        List gpsList = (List) dataMap.get("Gps");
        for (int i = 0; i < gpsList.size(); i++) {
            Map oneGps = ((Map) gpsList.get(i));
            String gpsStatus = null;
            try {
                gpsStatus = oneGps.get("Gps-Status").toString();
            } catch (Exception e) {
                break;
            }

            if ("0".equals(gpsStatus) || "2".equals(gpsStatus)) {
                //pro = 2;
                LongitudeType = oneGps.get("Longitude-Type").toString();
                Longitude = oneGps.get("Longitude").toString();
                DimensionType = oneGps.get("Latitude-Type").toString();
                Dimension = oneGps.get("Latitude").toString();
                break;
            }
        }
        if ("0".equals(Longitude) && pro == 2) {
            pro = 1;
        }
        String gpsContent = pro + "," + LongitudeType + Longitude + DimensionType + Dimension;
        body.append("1");
//        if (EmptyChecker.notEmpty(dataMap.get("Parameter-Label")) && !("-1".equals(dataMap.get("Parameter-Label")))) {
//            body.append("#" + dataMap.get("Parameter-Label"));
//        }
        //body.append("#TBBQ:01,M!02,B#SBJG:600#SOS:1#LJMS:1#");
        body.append("#TBBQ:01,M!02,B#SBJG:60#SOS:1#ZXWZ:" + gpsContent + "#LJMS:1#");
        String reBody = body.toString();

        //回复的内容
        StringBuilder content = new StringBuilder();
        content.append("[");
        //流水号
        content.append(TimeUtil.getSerialNumber());
        content.append(",");
        //注册id
        content.append(dataMap.get("IMSI-id").toString().substring(4));
        content.append(",");
        //回复协议
        content.append("T182");
        content.append(",");
        //报文体长度
        content.append(reBody.length());
        content.append(",");
        //报文体
        content.append(reBody);
        content.append("]");
        String reContent = content.toString();

        //所有回复内容
        StringBuilder callMsg = new StringBuilder();
        callMsg.append("HTTP/1.1 200 OK\n");
        callMsg.append("Server:IbabyServer\n");

        callMsg.append("Content-Length:" + (reContent.length()) + "\n");
        callMsg.append("gbk-length:" + (reContent.length()) + "\n\n");
        callMsg.append(reContent);

        String reCallMsg = callMsg.toString();

        log.info("回复内容");
        log.info(reCallMsg);

        pw.print(reCallMsg);
        pw.flush();
    }
}